package cn.iocoder.yudao.framework.common.exception;

import cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants;
import lombok.experimental.UtilityClass;

import java.nio.ByteBuffer;
import java.util.*;

/**
 * FIXME 新增
 * <pre>
 * OOoO0OOoO0OOOooo0oOOOO0OOOOO0oooOO0ooOOO0Ooooo0OOOOo0ooooO0OOooo0Ooooo0OOOOO
 * 参数有效性断言工具类，断言失败则抛出{@link KnownServiceException}，全局异常处理器捕获处理不打印堆栈信息日志。
 *
 * @author 山野羡民（1032694760@qq.com）
 * @since 2023/10/15
 * @see org.springframework.util.Assert
 * @see cn.hutool.core.lang.Assert
 * //@see com.baomidou.mybatisplus.core.toolkit.Assert
 * //@see org.apache.http.util.Asserts
 * @see org.apache.commons.lang3.Validate
 * OOoO0OOoO0OOOooo0oOOOO0OOOOO0oooOO0ooOOO0Ooooo0OOOOo0ooooO0OOooo0Ooooo0OOOOO
 */
@SuppressWarnings("unused")
@UtilityClass
public final class Assertions {

    public static void isTrue(boolean expression, String errorMsg) throws KnownServiceException {
        if (!expression) {
            throw new KnownServiceException(errorMsg);
        }
    }

    public static void isTrue(boolean expression) throws KnownServiceException {
        isTrue(expression, "Must be true");
    }

    public static void isFalse(boolean expression, String errorMsg) throws KnownServiceException {
        if (expression) {
            throw new KnownServiceException(errorMsg);
        }
    }

    public static void isFalse(boolean expression) throws KnownServiceException {
        isFalse(expression, "Must be false");
    }

    public static void notNull(Object object, String errorMsg) throws KnownServiceException {
        if (object == null) {
            throw new KnownServiceException(errorMsg);
        }
    }

    public static void notNull(Object object) throws KnownServiceException {
        notNull(object, "Must not null");
    }

    public static void notBlank(String string) throws KnownServiceException {
        notBlank(string, "Must not blank");
    }

    public static void notBlank(String string, String errorMsg) throws KnownServiceException {
        if (string == null || string.trim().isEmpty()) {
            throw new KnownServiceException(errorMsg);
        }
    }

    public static void notEmpty(String string) throws KnownServiceException {
        notEmpty(string, "String must contain at least one character");
    }

    public static void notEmpty(String string, String errorMsg) throws KnownServiceException {
        if (string == null || string.trim().isEmpty()) {
            throw new KnownServiceException(errorMsg);
        }
    }

    public static <T> void notEmpty(T[] objects) throws KnownServiceException {
        notEmpty(new ArrayList<>(List.of(objects)));
    }

    public static void notEmpty(Collection<?> collection) throws KnownServiceException {
        notEmpty(collection, "Collection must contain at least one element");
    }

    public static void notEmpty(Collection<?> collection, String errorMsg) throws KnownServiceException {
        if (collection == null || collection.isEmpty()) {
            throw new KnownServiceException(errorMsg);
        }
    }

    public static void notEmpty(Map<?, ?> map, String errorMsg) throws KnownServiceException {
        if (map == null || map.isEmpty()) {
            throw new KnownServiceException(errorMsg);
        }
    }

    public static void notEmpty(Map<?, ?> map) throws KnownServiceException {
        notEmpty(map, "Map must contain at least one entry");
    }

    public static void notEquals(Object actual, Object expected, String msg) throws KnownServiceException {
        isFalse(Objects.equals(actual, expected), msg);
    }

    public static void instanceOf(Class<?> type, Object obj, String errorMsg) throws KnownServiceException {
        notNull(type, "Type must not be null");
        if (!type.isInstance(obj)) {
            throw new KnownServiceException(errorMsg);
        }
    }

    public static void instanceOf(Class<?> type, Object obj) throws KnownServiceException {
        instanceOf(type, obj, "Type must not be instance of " + obj.getClass().getName());
    }

    public static void equals(byte[] left, byte[] right) throws KnownServiceException {
        // 字节数组断言，参阅 <a href="http://github.com/airlift/aircompressor">AbstractTestCompression.java</a>
        int leftOffset = 0;
        int leftLength = left.length;
        int rightOffset = 0;
        int rightLength = right.length;
        for (int i = 0, n = Math.min(leftLength, rightLength); i < n; i++) {
            byte l = left[leftOffset + i];
            byte r = right[rightOffset + i];
            if (l != r) {
                throw new KnownServiceException(String.format("ByteArray differ at position %s: 0x%02X vs 0x%02X", i, l, r));
            }
        }
        if (leftLength != rightLength) {
            throw new KnownServiceException(String.format("Bytes length differ: %s vs %s", leftLength, rightLength));
        }
    }

    public static void equals(ByteBuffer left, ByteBuffer right) throws KnownServiceException {
        // 字节缓冲区断言，参阅 <a href="http://github.com/airlift/aircompressor">AbstractTestCompression.java</a>
        int leftPosition = left.position();
        int rightPosition = right.position();
        int leftRemaining = left.remaining();
        int rightRemaining = right.remaining();
        for (int i = 0, n = Math.min(leftRemaining, rightRemaining); i < n; i++) {
            byte l = left.get(leftPosition + i);
            byte r = right.get(rightPosition + i);
            if (l != r) {
                throw new KnownServiceException(String.format("ByteBuffer differ at position %s: 0x%02X vs 0x%02X", i, l, r));
            }
        }
        if (leftRemaining != rightRemaining) {
            throw new KnownServiceException(String.format("Bytes length differ: %s vs %s", leftRemaining, rightRemaining));
        }
    }

    public static void equals(Object actual, Object expected, String msg) throws KnownServiceException {
        if (actual == null || expected == null) {
            return;
        }
        if (actual instanceof byte[] a && expected instanceof byte[] b) {
            if (!Arrays.equals(a, b)) {
                throw new KnownServiceException(msg);
            }
            return;
        }
        if (actual instanceof int[] a && expected instanceof int[] b) {
            if (!Arrays.equals(a, b)) {
                throw new KnownServiceException(msg);
            }
            return;
        }
        if (actual instanceof long[] a && expected instanceof long[] b) {
            if (!Arrays.equals(a, b)) {
                throw new KnownServiceException(msg);
            }
            return;
        }
        if (actual instanceof char[] a && expected instanceof char[] b) {
            if (!Arrays.equals(a, b)) {
                throw new KnownServiceException(msg);
            }
            return;
        }
        if (!Objects.equals(actual, expected)) {
            throw new KnownServiceException(msg);
        }
    }

    public static void owner(Long actualOwnerId, Long expectedOwnerId) throws KnownServiceException {
        if (actualOwnerId == null || actualOwnerId <= 0) {
            return;
        }
        if (expectedOwnerId == null || expectedOwnerId <= 0) {
            return;
        }
        if (!Objects.equals(actualOwnerId, expectedOwnerId)) {
            throw new KnownServiceException(GlobalErrorCodeConstants.FORBIDDEN);
        }
    }

}
